package com.yungu.swift.lbs.dao;


import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.lbs.model.DriverLocation;
import com.yungu.swift.lbs.model.DriverPoint;
import com.yungu.swift.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Component
public class MongoDaoHelper {

    /**
     * 检索结果件数限制
     */
    public static final int LIMIT_CNT = 100;
    /**
     * 最大距离（单位：米）
     */
    public static final long MAX_DISTANCE = 10000;
    /**
     * 最大距离（单位：米）
     */
    public static final double EARTH_RADIUS = 6378137d;

    private static MongoOperations mongoOperations;

    @Autowired
    public void setMongoOperations(MongoOperations mongoOperations) {
        MongoDaoHelper.mongoOperations = mongoOperations;
    }

    /**
     * 插入司机位置点
     *
     * @param point
     */
    public static void insertDriverPoint(DriverPoint point) {
        // 先删除后插入
        Query query = new Query();
        query.addCriteria(new Criteria("driverUuid").is(point.getDriverUuid()));
        mongoOperations.findAndRemove(query, DriverPoint.class);
        mongoOperations.insert(point);
    }

    /**
     * 插入司机定位点
     *
     * @param driverLocation
     */
    public static void insert(DriverLocation driverLocation) {
        mongoOperations.insert(driverLocation);
    }

    /**
     * 司机点列表
     *
     * @param driverPoint
     * @return
     */
    public static List<DriverPoint> findDriverPoint(DriverPoint driverPoint) {
        Query query = new Query();
        query.with(new Sort(new Order(Direction.DESC, "uploadTime")));
        query.limit(LIMIT_CNT);
        if (!StringUtils.isEmpty(driverPoint.getDriverUuid())) {
            query.addCriteria(new Criteria("driverUuid").is(driverPoint.getDriverUuid()));
        }
        if (!StringUtils.isNull(driverPoint.getStatus())) {
            query.addCriteria(new Criteria("status").is(driverPoint.getStatus()));
        }
        List<DriverPoint> lstDriverPoint = mongoOperations.find(query, DriverPoint.class);
        return lstDriverPoint;
    }

    /**
     * 司机定位列表
     *
     * @param driverLocation
     * @return
     */
    public static List<DriverLocation> findDriverLocation(DriverLocation driverLocation) {
        Query query = new Query();
        query.with(new Sort(new Order(Direction.DESC, "uploadTime")));
        query.limit(1);
        if (!StringUtils.isEmpty(driverLocation.getDriverUuid())) {
            query.addCriteria(new Criteria("driverUuid").is(driverLocation.getDriverUuid()));
        }
        List<DriverLocation> lstDriverLocation = mongoOperations.find(query, DriverLocation.class);
        return lstDriverLocation;
    }


    public static DriverLocation findNewestOrderLocation(String orderUuid, String appid) {
        return findNewestOrderLocation(orderUuid, null, appid);
    }

    /**
     * 获得司机某个状态的最新定位点
     *
     * @param orderUuid
     * @param positionType
     * @param appid
     * @return
     */
    public static DriverLocation findNewestOrderLocation(String orderUuid, String positionType, String appid) {
        Query query = new Query();
        query.with(new Sort(new Order(Direction.DESC, "uploadTime")));
        query.limit(LIMIT_CNT);
        query.addCriteria(new Criteria("orderUuid").is(orderUuid));
        query.addCriteria(new Criteria("appid").is(appid));
        if (StringUtils.isNotEmpty(positionType)) {
            query.addCriteria(new Criteria("positionType").is(positionType));
        }
        List<DriverLocation> lstDriverLocation = mongoOperations.find(query, DriverLocation.class);
        if (lstDriverLocation != null && lstDriverLocation.size() > 0) {
            return lstDriverLocation.get(0);
        }
        return new DriverLocation();
    }

    /**
     * 获得某个订单的定位点
     *
     * @param orderUuid
     * @param appid
     * @return
     */
    public static List<DriverLocation> findOrderMapPoint(String orderUuid, String appid) {
        Query query = new Query();
        query.with(new Sort(new Order(Direction.ASC, "uploadTime")));
        query.addCriteria(new Criteria("orderUuid").is(orderUuid));
        query.addCriteria(new Criteria("appid").is(appid));
        List<DriverLocation> lstDriverLocation = mongoOperations.find(query, DriverLocation.class);
        if (lstDriverLocation != null && lstDriverLocation.size() > 0) {
            return lstDriverLocation;
        }
        return new ArrayList<>();
    }


    /**
     * 获得某个司机的定位点
     *
     * @param driverUuid
     * @param appid
     * @return
     */
    public static List<DriverLocation> findDriverTodayMapPoint(String driverUuid, String appid) {
        Query query = new Query();
        query.with(new Sort(new Order(Direction.ASC, "uploadTime")));
        query.addCriteria(new Criteria("driverUuid").is(driverUuid));
        query.addCriteria(new Criteria("appid").is(appid));
        //获取当天的
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String todayStr = sdf.format(new Date());
            String todayStrStart = todayStr + " 00:00:00";
            String todayStrEnd = todayStr + " 23:59:59";
            Date todayStart = sdf2.parse(todayStrStart);
            Date todayEnd = sdf2.parse(todayStrEnd);
            query.addCriteria(new Criteria("uploadTime").gte(todayStart).lte(todayEnd));
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
        List<DriverLocation> lstDriverLocation = mongoOperations.find(query, DriverLocation.class);
        if (lstDriverLocation != null && lstDriverLocation.size() > 0) {
            return lstDriverLocation;
        }
        return new ArrayList<>();
    }


    /**
     * 根据经纬度查找附近司机
     *
     * @param type     司机类型（出租车、专车、拼车等）
     * @param lng      经度
     * @param lat      纬度
     * @param appid    应用ID
     * @param distance 检索距离（单位：米）
     * @param maxNum   检索结果最大司机数
     **/
    public static List<DriverPoint> geoNear(int type, double lng, double lat, String appid, int distance, int maxNum) {
        return geoNearMethod(type, lng, lat, appid, distance, maxNum, 0);
    }

    /**
     * 根据经纬度查找附近司机(在线)
     **/
    public static List<DriverPoint> geoNearOnline(int type, double lng, double lat, String appid, int distance, int maxNum) {
        return geoNearMethod(type, lng, lat, appid, distance, maxNum, DriverPoint.STATUS_ONLINE);
    }

    private static List<DriverPoint> geoNearMethod(int type, double lng, double lat, String appid, int distance, int maxNum,
                                                         int status) {
        org.springframework.data.geo.Point point = new org.springframework.data.geo.Point(lng,lat);
        Criteria criteria = Criteria.where("coordinate").nearSphere(point);
        criteria.maxDistance(distance / MongoDaoHelper.EARTH_RADIUS);
        Query query = new Query(criteria);
        // 司机类型
        query.addCriteria(new Criteria("type").is(type));
        // 应用ID
        query.addCriteria(new Criteria("appid").is(appid));
        if (status != 0) {
            //车状态
            query.addCriteria(new Criteria("status").is(status));
        }
        //寻找最近5分钟内，有上传位置的司机
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MINUTE, -5);
        query.addCriteria(new Criteria("uploadTime").gte(calendar.getTime()));
        query.with(new Sort(new Order(Direction.DESC, "uploadTime")));
        query.with(new Sort(new Order(Direction.DESC, "driverUuid")));
        return mongoOperations.find(query, DriverPoint.class);
    }

    public static List<DriverLocation> getAllNewsDriverPoint(int type, int carType, String appid) {
        Query query = new Query();
        if (type != CommonConstant.BUSINESS_ALL) {
            // 业务类型
            query.addCriteria(new Criteria("type").is(type));
        }
        if (carType != CommonConstant.CARTYPE_ALL) {
            // 业务类型
            query.addCriteria(new Criteria("carModelType").is(String.valueOf(carType)));
        }
        //这边只取AUTO点
        query.addCriteria(new Criteria("positionType").is("AUTO"));
        query.addCriteria(new Criteria("appid").is(appid));
        //寻找最近5分钟内，有上传位置的司机并且排序
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MINUTE, -5);
        query.addCriteria(new Criteria("uploadTime").gte(calendar.getTime()));
        query.with(new Sort(new Order(Direction.DESC, "driverUuid")));
        query.with(new Sort(new Order(Direction.DESC, "uploadTime")));
        return mongoOperations.find(query, DriverLocation.class);
    }

    public static List<DriverLocation> findOrderDuringTheTripPoints(String orderUuid, String appid) {
        //乘客上车
        DriverLocation ckscPoint = findNewestOrderLocation(orderUuid, "CKSC", appid);
        //乘客下车
        DriverLocation ckxcPoint = findNewestOrderLocation(orderUuid, "CKXC", appid);
        //行程中必须要有乘客上车点
        if (null != ckscPoint && null != ckscPoint.getUploadTime()) {
            //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Query query = new Query();
            query.addCriteria(new Criteria("orderUuid").is(orderUuid));
            query.addCriteria(new Criteria("appid").is(appid));
            //可以没有乘客下车点
            if (null != ckxcPoint && null != ckxcPoint.getUploadTime()) {
                query.addCriteria(new Criteria("uploadTime").gte(ckscPoint.getUploadTime())
                        .lte(ckxcPoint.getUploadTime()));
            } else {
                query.addCriteria(new Criteria("uploadTime").gte(ckscPoint.getUploadTime()));
            }
            query.with(new Sort(new Order(Direction.ASC, "uploadTime")));
            List<DriverLocation> lstDriverLocation = mongoOperations.find(query, DriverLocation.class);
            if (lstDriverLocation != null && lstDriverLocation.size() > 0) {
                return lstDriverLocation;
            }
        }
        return new ArrayList<>();
    }
}
